/*
 * Created on 15-dic-2005
 *
 */
package cra.clima.gsrad;

import junit.framework.TestCase;
import net.sf.xqore.math.XQMath;
import cra.clima.core.interfaces.gsrad.IAGSRadStrategy;
import cra.clima.core.interfaces.gsrad.IRadData;

/**
 * @author chcassan
 * 
 * Java implementation of the Nunit created to test c# classes.
 * 
 *  
 */
public class GSRadDotNetTest extends TestCase {
	
	private double delta;
	
	public GSRadDotNetTest() {
		super();
		this.delta = 0.01;
	}
	
	public void testBristowCampbellDotNet() {
		double[][] rangedayRangemonth = { { 15, 11 }, { 2, 10 }, { 2, 15 },
				{ 20, 10 }, { 15, 15 } };
		double[] results = { 14.30, 0.87, 0.59, 14.96, 13.42 };
		
		//to test calling the internal class
		GSRBristowCampbellStrategy algo = new GSRBristowCampbellStrategy();
		
		RadData rd = new RadData();
		BristowCampbellParameters bcParams = new BristowCampbellParameters();
		
		//set parameters
		bcParams.setB(0.15);
		rd.setClearSkyTransmissivity(0.75);
		rd.setExtraTerrestrialRadiation(20);
		rd.setSlopeAspectFactor(1);
		int caso;
		for (caso = 0; caso < 5; caso++) {
			rd.setAirTemperatureDailyRange(rangedayRangemonth[caso][0]);
			rd.setAirTemperatureMonthlyRange(rangedayRangemonth[caso][1]);
			
			// Eval:
			algo.setParameters(bcParams);
			GSRadContext gsr = new GSRadContext((IAGSRadStrategy) algo);
			gsr.evaluate(rd);
			
			//Test:
			assertEquals("", results[caso], XQMath.round(rd
					.getGlobalSolarRadiation(), 2), delta);
		}
	}
	
	public void testCampbellDonatelliDotNet() {
		
		double[][] tminTncTavgRange = { { 22, 20, 30, 16 }, { 0, 30, 2, 4 },
				{ 10, 30, 20, 20 }, { 22, 40, 30, 16 } };
		
		double[] results = { 14.95, 3.13, 14.86, 14.41 };
		
		// Strategy selected:
		GSRCampbellDonatelliStategy algo = new GSRCampbellDonatelliStategy();
		
		// Data needed:
		IRadData rd = new RadData();
		CampbellDonatelliParameters cdParams = new CampbellDonatelliParameters();
		
		//set parameters
		cdParams.setB(0.35);
		
		rd.setClearSkyTransmissivity(0.75);
		rd.setExtraTerrestrialRadiation(20);
		rd.setSlopeAspectFactor(1);
		
		for (int caso = 0; caso < 4; caso++) {
			rd.setAirTemperatureMin(tminTncTavgRange[caso][0]);
			cdParams.setTnc(tminTncTavgRange[caso][1]);
			rd.setAirTemperatureDailyAverage(tminTncTavgRange[caso][2]);
			rd.setAirTemperatureDailyRange(tminTncTavgRange[caso][3]);
			
			// Evaluate!!
			algo.setParameters(cdParams);
			GSRadContext gsr = new GSRadContext((IAGSRadStrategy) algo);
			gsr.evaluate(rd);
			
			// Test it!!
			assertEquals("global solar radiation:", results[caso], XQMath
					.round(rd.getGlobalSolarRadiation(), 2), delta);
		}
		
	}
	
	public void testCSTThorntonRunningDotNet() {
		double[][] solarElevationAverage = {
				{ 0, 0, 0, 0, 0, 0.114, 0.281, 0.449, 0.606, 0.740, 0.843,
					0.908, 0.930, 0.908, 0.843, 0.740, 0.606, 0.449, 0.281,
					0.114, 0, 0, 0, 0 },
					{ 0, 0, 0, 0, 0, 0, 0, 0, 0.062, 0.198, 0.302, 0.368, 0.390,
						0.368, 0.302, 0.198, 0.062, 0, 0, 0, 0, 0, 0, 0 } };
		double[][] resultsCST = { { 0.78, 0.57 }, { 0.78, 0.58 } };
		//to test calling the internal class
		CSTThorntonRunningStrategy sa = new CSTThorntonRunningStrategy();
		
		IRadData rd = new RadData();
		ThorntonRunningParameters trParams = new ThorntonRunningParameters();
		//set parameters
		trParams.setActualVaporPressure(-0.000061);
		trParams.setNadirAtmosphericTransmittance(0.87);
		trParams.setSlopeVaporPressure(1);
		
		for (int z = 0; z < 2; z++) {
			rd.setElevation(0, 1, 1);
			if (z == 1) {
				rd.setElevation(200, 1, 1);
			}
			for (int sElev = 0; sElev < 2; sElev++) {
				for (int h = 0; h < 24; h++) {
					rd.setSolarElevation(solarElevationAverage[sElev][h], h);
				}
				
				sa.setParameters(trParams);
				GSRadContext i = new GSRadContext((IAGSRadStrategy) sa);
				i.evaluate(rd);
				assertEquals(resultsCST[z][sElev], rd
						.getClearSkyTransmissivity(), delta);
			}
		}
	}
	
	public void testDonatelliBellocchiDotNet() {
		double[][] rangedayRangeweek = { { 15, 11 }, { 2, 5 }, { 2, 8 },
				{ 20, 12 } };
		int[] dayOfTheYear = { 1, 90, 172 };
		
		double[][][] results = {
				{ { 16.49, 4.03, 2.65, 16.51 }, { 16.10, 3.94, 2.59, 16.12 },
					{ 15.02, 3.67, 2.41, 15.03 } },
					{ { 16.51, 4.04, 2.65, 16.52 }, { 16.32, 3.99, 2.62, 16.34 },
						{ 13.99, 3.42, 2.25, 14.00 } } };
		//to test calling the internal class
		GSRDonatelliBellocchiStrategy sa = new GSRDonatelliBellocchiStrategy();
		//to test the strategy implementation
		
		RadData rd = new RadData();
		DonatelliBellocchiParameters dbParams = new DonatelliBellocchiParameters();
		
		//set parameters
		dbParams.setB(0.35);
		dbParams.setC1(0.1);
		dbParams.setReverse(false);
		rd.setClearSkyTransmissivity(0.75);
		rd.setExtraTerrestrialRadiation(20.0);
		rd.setSlopeAspectFactor(1);
		int doy;
		int c2;
		int caso;
		for (c2 = 0; c2 < 2; c2++) {
			dbParams.setC2(0.25);
			if (c2 == 1) {
				dbParams.setC2(1.0);
			}
			for (doy = 0; doy < 3; doy++) {
				rd.setCurrentDay(dayOfTheYear[doy]);
				for (caso = 0; caso < 4; caso++) {
					rd.setAirTemperatureDailyRange(rangedayRangeweek[caso][0]);
					rd.setAirTemperatureWeeklyRange(rangedayRangeweek[caso][1]);
					sa.setParameters(dbParams);
					GSRadContext i = new GSRadContext((IAGSRadStrategy) sa);
					i.evaluate(rd);
					assertEquals("", results[c2][doy][caso], XQMath.round(rd
							.getGlobalSolarRadiation(), 2), delta);
				}
			}
		}
	}
	
	public void testGarciaHoogenboomDotNet() {
		StateEnum[] resultStatusWet = { StateEnum.State_Dry,
				StateEnum.State_Wet };
		double[] resultLatitude = { 44, -20 };
		double[][] resultsGSR = { { 15.236, 17.464 }, { 12.884, 15.614 } };
		//to test calling the internal class
		GSRGarciaHogenboom algo = new GSRGarciaHogenboom();
		//to test the strategy implementation
		
		RadData rd = new RadData();
		GarciaHogenboomParameters ghParams = new GarciaHogenboomParameters();
		//set parameters
		ghParams.setAdjustmentFactorGBARDry(0.01);
		ghParams.setAdjustmentFactorGBARWet(0.05);
		ghParams.setAdjustmentFactorGNoise(2);
		ghParams.setGsrYearlyAmplitudeDry(4.5);
		ghParams.setGsrYearlyAmplitudeWet(4);
		ghParams.setGsrYearlyMeanDry(12.5);
		ghParams.setGsrYearlyMeanDry(8);
		
		rd.setLatitude(44);
		rd.setCurrentDay(180);
		rd.setGlobalSolarRadiationResidual(0.2);
		int caso;
		int j;
		for (caso = 0; caso < 2; caso++) {
			ghParams.setDayStatus(resultStatusWet[caso]);
			for (j = 0; j < 2; j++) {
				rd.setLatitude(resultLatitude[j]);
				algo.setParameters(ghParams);
				GSRadContext gsr = new GSRadContext((IAGSRadStrategy) algo);
				gsr.evaluate(rd);
				assertEquals("", resultsGSR[j][caso], rd
						.getGlobalSolarRadiation(), delta);
			}
		}
	}
	
	public void testRichardsonDotNet() {
		double[][][][] resultsGSRResidual = {
				{ { { 0, 0 }, { 0, 0 } },
					{ { -1.615, -0.255 }, { -0.054, -0.054 } },
					{ { 0.326, 0.353 }, { 0.104, 0.104 } } },
					{ { { -0.612, -1.172 }, { -1.712, -1.712 } },
						{ { -2.227, -1.427 }, { -1.766, -1.766 } },
						{ { -0.286, -0.819 }, { -1.608, -1.608 } } },
						{ { { 0.738, 0.54 }, { 0.683, 0.683 } },
							{ { -0.876, 0.285 }, { 0.63, 0.63 } },
							{ { 1.065, 0.894 }, { 0.787, 0.787 } } } };
		double[][][][] resultsGSR = {
				{ { { 23.0, 23.0 }, { 12.5, 25.1 } },
					{ { 16.5, 22.0 }, { 12.3, 24.9 } },
					{ { 24.3, 24.4 }, { 13.0, 25.5 } } },
					{ { { 20.6, 18.3 }, { 5.7, 18.2 } },
						{ { 14.1, 17.3 }, { 5.5, 18.0 } },
						{ { 21.9, 19.7 }, { 6.1, 18.7 } } },
						{ { { 26.0, 25.2 }, { 15.3, 27.8 } },
							{ { 19.5, 24.1 }, { 15.1, 27.6 } },
							{ { 27.3, 26.6 }, { 15.7, 28.2 } } } };
		//to test calling the internal class
		GSRRichardsonStrategy algo = new GSRRichardsonStrategy();
		//to test the strategy implementation
		RadData rd = new RadData();
		RichardsonParameters rParams = new RichardsonParameters();
		
		//set parameters
		rParams.setNumberOfDaysInMonth(30);
		rParams.setNumberOfWetDaysInMonth(5);
		rParams.setRadiationMonthlyAverage(23);
		rParams.setRadiationMonthlyStandardDeviation(4);
		rParams.setScalingFactorWetDry(0.5);
		
		int rnd;
		int res;
		int sep;
		int caso;
		for (rnd = 0; rnd < 3; rnd++) {
			for (res = 0; res < 3; res++) {
				for (sep = 0; sep < 2; sep++) {
					if (sep == 1) {
						rParams
						.setSelectedMethod(MethodEnum.Method_NoSeparated);
					} else {
						rParams.setSelectedMethod(MethodEnum.Method_Separated);
					}
					for (caso = 0; caso < 2; caso++) {
						
						if (caso == 1) {
							rParams.setSelectedState(StateEnum.State_Dry);
						} else {
							rParams.setSelectedState(StateEnum.State_Wet);
						}
						//call internal class
						rd
						.setGlobalSolarRadiationResidual(resultsGSRResidual[rnd][res][sep][caso]);
						
						// Evaluate:
						algo.setParameters(rParams);
						GSRadContext i = new GSRadContext(
								(IAGSRadStrategy) algo);
						i.evaluate(rd);
						// Test:
						assertEquals("", resultsGSR[rnd][res][sep][caso],
								XQMath.round(rd.getGlobalSolarRadiation(), 1),
								delta);
					}
				}
			}
		}
	}
	
	// TODO: Test GSRDonatelliBellocchiDotNet
	
	public void testSAFSlopeAspectFactorDotNet() {
		double[][] solarElevation = {
				{ 0, 0, 0, 0, 0, 0.114, 0.281, 0.449, 0.606, 0.740, 0.843,
					0.908, 0.930, 0.908, 0.843, 0.740, 0.606, 0.449, 0.281,
					0.114, 0, 0, 0, 0 },
					{ 0, 0, 0, 0, 0, 0, 0, 0, 0.062, 0.198, 0.302, 0.368, 0.390,
						0.368, 0.302, 0.198, 0.062, 0, 0, 0, 0, 0, 0, 0 } };
		int[] sunRise = { 5, 9 };
		int[] sunSet = { 19, 16 };
		
		double[] hourAngle = { -180, -165, -150, -135, -120, -105, -90, -75,
				-60, -45, -30, -15, 0, 15, 30, 45, 60, 75, 90, 105, 120, 135,
				150, 165 };
		double[][] slopeAspect = { { 40, 180 }, { 0, 0 }, { 0, 30 }, { 40, 0 },
				{ 30, 30 }, { 40, 70 }, { 40, 90 } };
		double[][] resultSlopeAspectFactor = {
				{ 0.7, 1, 1, 0.8, 0.9, 0.9, 0.9 },
				{ 0, 1, 1, 2.8, 2.2, 1.6, 1.1 } };
		//to test calling the internal class
		SAFSlopeAspectFactorStrategy algo = new SAFSlopeAspectFactorStrategy();
		IRadData rd = new RadData();
		rd.setLatitude(45);
		int caso;
		int doy;
		int h;
		for (doy = 0; doy < 2; doy++) {
			rd.setHourSunrise(sunRise[doy]);
			rd.setHourSunset(sunSet[doy]);
			if (doy == 0) {
				rd.setSolarDeclination(0.409);
			} else {
				rd.setSolarDeclination(-0.385);
			}
			for (h = 0; h < 24; h++) {
				rd.setHourAngle(hourAngle[h], h);
				rd.setSolarElevation(solarElevation[doy][h], h);
			}
			for (caso = 0; caso < 5; caso++) {
				rd.setAngleSlope(slopeAspect[caso][0]);
				rd.setAngleAspect(slopeAspect[caso][1]);
				//to test the strategy implemetation
				//				to test the strategy implementation
				GSRadContext gsr = new GSRadContext((IAGSRadStrategy) algo);
				
				gsr.evaluate(rd);
				assertEquals("aa ", resultSlopeAspectFactor[doy][caso], XQMath
						.round(rd.getSlopeAspectFactor(), 1), 0.1);
			}
		}
	}
	
	public void testSlopeAspectDotNet() {
		double[][][] dataElevation = {
				{ { 10, 10, 10 }, { 12, 12, 12 }, { 13, 13, 13 } },
				{ { 12, 12, 12 }, { 15, 12, 12 }, { 15, 15, 13 } },
				{ { 6, 7, 7 }, { 5, 7, 7 }, { 8, 7, 8 } },
				{ { 7, 7, 7 }, { 5, 7, 7 }, { 7, 7, 7 } },
				{ { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } } };
		double[][] resultSlopeAspect = { { 56.3, 0 }, { 58.0, 38.7 },
				{ 36.1, 301.0 }, { 26.6, 270.0 }, { 0, 0 } };
		// Parameters:
		IRadData rd = new RadData();
		rd.setCellSize(1);
		
		int caso;
		int r;
		int c;
		for (caso = 0; caso < 5; caso++) {
			for (r = 0; r < 3; r++) {
				for (c = 0; c < 3; c++) {
					rd.setElevation(dataElevation[caso][r][c], r, c);
				}
			}
			
			// Test!!
			SASlopeAspectStrategy sa = new SASlopeAspectStrategy();
			GSRadContext i = new GSRadContext((IAGSRadStrategy) sa);
			i.evaluate(rd);
			assertEquals("", resultSlopeAspect[caso][0], XQMath.round(rd
					.getAngleSlope(), 1), delta);
			assertEquals("", resultSlopeAspect[caso][1], XQMath.round(rd
					.getAngleAspect(), 1), delta);
		}
	}
	
	public void testBDRLiuJordanDotNet() {
		double resultBeam = 27.32;
		double resultDiffuse = 0.68;
		double resultReflected = 0.00;
		//to test calling the internal class
		BDRLiuJordanStrategy algo = new BDRLiuJordanStrategy();
		//to test the strategy implementation
		IRadData rd = new RadData();
		LiuJordanParameters ljParams = new LiuJordanParameters();
		//set parameters
		ljParams.setLinkedTurbidityFactor(3);
		rd.setExtraTerrestrialRadiation(34);
		rd.setGlobalSolarRadiation(28);
		rd.setSlopeAspectFactor(1);
		rd.setElevation(0, 1, 1);
		rd.setClearSkyTransmissivity(0.75);
		rd.setAngleSlope(0);
		rd.setAlbedo(0.2);
		
		algo.setParameters(ljParams);
		GSRadContext gsr = new GSRadContext((IAGSRadStrategy) algo);
		
		gsr.evaluate(rd);
		assertEquals(resultBeam, rd.getRadiationBeam(), delta);
		assertEquals(resultDiffuse, rd.getRadiationDiffuseSky(), delta);
		assertEquals(resultReflected, rd.getRadiationReflectedSoil(), delta);
	}
	
	public void testGSRSupitVanKappelDotNet() {
		double[] dailyTemperatureRange = { 15, 2, 1, 18, 9, 15, 1, 22, 15 };
		int[] cloudCover = { 3, 8, 8, 0, 4, 2, 8, 0, 1 };
		double[] extraterrestrialRadiation = { 17.45, 16.19, 6.67, 19.68,
				26.50, 29.28, 33.37, 37.62, 36.07 };
		double[] resultsGSR = { 10.8, 1.8, 0.5, 14.4, 13.7, 19.0, 2.7, 28.8,
				24.3 };
		//to test calling the internal class
		GSRSupitVanKappelStrategy algo = new GSRSupitVanKappelStrategy();
		//to test the strategy implementation
		IRadData rd = new RadData();
		SupitVanKappelParameters svkParams = new SupitVanKappelParameters();
		//set parameters
		svkParams.setAdjustmentFactor(0);
		svkParams.setCloudCoverCoefficent(0.39);
		svkParams.setTemperatureRangeCoefficent(0.08);
		rd.setSlopeAspectFactor(1);
		int caso;
		for (caso = 0; caso < 9; caso++) {
			svkParams.setCloudCover(cloudCover[caso]);
			rd.setAirTemperatureDailyRange(dailyTemperatureRange[caso]);
			rd.setExtraTerrestrialRadiation(extraterrestrialRadiation[caso]);
			
			algo.setParameters(svkParams);
			GSRadContext gsr = new GSRadContext((IAGSRadStrategy) algo);
			gsr.evaluate(rd);
			assertEquals(resultsGSR[caso], rd.getGlobalSolarRadiation(), delta);
		}
	}
	
	public void testHBDRLiuJordanHourly() {
		
		double[] gsradHourly = {0.00,0.00,0.00,0.00,0.00,0.36,0.90,1.43,
				1.93,2.36,2.69,2.89,2.97,2.90,2.69,2.36,
				1.93,1.43,0.90,0.36,0.00,0.00,0.00,0.00}; 
		double[] slAsFaHourly = {0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0};
		double[] solarElevation = {0,0,0,0,0,0.114,0.285,0.466,0.651,0.833,1.003,1.138,
				1.195,1.138,1.003,0.833,0.651,0.466,0.285,0.114,0,0,0,0};
		double[] resultBeamHourly = {0,0,0,0,0,0.322,0.833,1.342,1.831,2.257,2.588,2.79,2.872,
				2.801,2.588,2.257,1.831,1.342,0.833,0.322,0,0,0,0};
		double[] resultDiffuseHourly = {0,0,0,0,0,0.038,0.067,0.088,0.099,0.103,0.102,0.1,0.098,
				0.099,0.102,0.103,0.099,0.088,0.067,0.038,0,0,0,0};
		double[] resultReflectedHourly = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
		double resultBeam = 26.809;
		double resultDiffuse = 1.291;
		double resultReflected = 0;
		//to test calling the internal class
		HBDRLiuJordanHourlyStrategy sa = new HBDRLiuJordanHourlyStrategy();
		IRadData rd = new RadData();
		LiuJordanHourlyParameters ljhParams = new LiuJordanHourlyParameters();
		//set parameters
		ljhParams.setHourlyLinkedTurbidityFactor(3);
		for (int h=0;h<24;h++) {
		rd.setGlobalSolarRadiationHourly(gsradHourly[h],h);
		rd.setSlopeAspectFactorHourly(slAsFaHourly[h],h);
		rd.setSolarElevation(solarElevation[h],h);
		}
		rd.setElevation(0,1,1);
		rd.setClearSkyTransmissivity(0.75);
		rd.setAngleSlope(0);
		rd.setAlbedo(0.2);
		rd.setHourSunrise(5);  
		rd.setHourSunset(19);  
		rd.setCurrentDay(172);
		
		sa.setParameters(ljhParams);
		GSRadContext i = new GSRadContext((IAGSRadStrategy)sa);
		
		i.evaluate(rd);
		
		for (int h=0; h<24; h++)
		{
			assertEquals("B",resultBeamHourly[h], rd.getHourlyRadiationBeam(h),0.01);
			assertEquals("D",resultDiffuseHourly[h], rd.getHourlyRadiationDiffuseSky(h), 0.01);
			assertEquals("R",resultReflectedHourly[h], rd.getHourlyRadiationReflectedSoil(h), 0.01);
		}
		assertEquals("BD",resultBeam, rd.getRadiationBeam(), 0.01);
		assertEquals("DD",resultDiffuse, rd.getRadiationDiffuseSky(), 0.01);
		assertEquals("RD",resultReflected, rd.getRadiationReflectedSoil(), 0.01);
	}
	
	public void testERExtraterrestrialRadiationDotNet()
	{
		double[] resultsExtRad = {0.1,12,42,42,30,12,33,38,36 };
		double[] resultsDaylength = {1.7,10.9,20.5,15.3,12.5,9.0,12,12,12};
		double[] resultsHourSunset = {12.9,17.5,22.2,19.7,18.2,16.5,18,18,18};
		double[] Latitude = {-66,44,0};
		int[] DOY = {172,90,12};
		//to test calling the internal class
		ERExtraterrestrialRadiationStrategy sa = new ERExtraterrestrialRadiationStrategy();
		//to test the strategy implementation
		GSRadContext i = new GSRadContext((IAGSRadStrategy)sa);
		IRadData rd = new RadData();
		int k;
		int j;
		for (k=0; k<3; k++)
		{
			rd.setCurrentDay(DOY[k]);
			for (j=0; j<3; j++)
			{
				rd.setLatitude(Latitude[j]);
				i.evaluate(rd);
				assertEquals("ER",resultsExtRad[((j + 1) * 3 -3) + k],  XQMath.round(rd.getExtraTerrestrialRadiation(),1), 1);
				assertEquals("DL",resultsDaylength[((j + 1) * 3 -3) + k], XQMath.round(rd.getDayLength(),1), 0.1);
				assertEquals("HSS",resultsHourSunset[((j + 1) * 3 -3) + k], rd.getHourSunset(), 1);
			}
		}
	}
	
	public void testCSTWinslowEtAlDotNet()   
	{
		double[] latitude = {10,45,83};
		double[][] resultsCST = {{0.82,0.78,0.67},{0.83,0.79,0.68}}; 
		CSTWinslowEtAlStrategy sa = new CSTWinslowEtAlStrategy();
		//set parameters
		WinslowEtAlParameters weaParams = new WinslowEtAlParameters();
		weaParams.setAerosolTransmittance(1);
		IRadData rd = new RadData();
		rd.setAirTemperatureYearlyAverage(15);
		int z;
		int lat;
		for (z=0; z<2; z++)
		{
			rd.setElevation(0,1,1);
			if (z == 1){rd.setElevation(200,1,1);}
			for (lat=0; lat<3; lat++)
			{
				rd.setLatitude(latitude[lat]); 
				
				sa.setParameters(weaParams);
				GSRadContext i = new GSRadContext((IAGSRadStrategy)sa);
				i.evaluate(rd);
				assertEquals(resultsCST[z][lat], rd.getClearSkyTransmissivity(), 0.01);
			}
		}
	}
	
	
}